﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;


class ComplexNumber
{
    private double realPart;
    private double imaginaryPart;

    public double RealPart
    {
        get { return realPart; }
        set { realPart = value; }
    }
    
    public double ImaginaryPart
    {
        get { return imaginaryPart; }
        set { imaginaryPart = value; }
    }

    public ComplexNumber(double realPart, double imaginaryPart)
    {
        this.RealPart = realPart;
        this.ImaginaryPart = imaginaryPart;
    }

    public static ComplexNumber operator +(ComplexNumber first, ComplexNumber second)
    {
        ComplexNumber newNumber = new ComplexNumber(first.RealPart + second.RealPart,
            first.ImaginaryPart + second.ImaginaryPart);
        return newNumber;
    }

    public static ComplexNumber operator -(ComplexNumber first, ComplexNumber second)
    {
        ComplexNumber newNumber = new ComplexNumber(first.RealPart - second.RealPart,
            first.ImaginaryPart - second.ImaginaryPart);
        return newNumber;
    }

    public static ComplexNumber operator *(ComplexNumber first, ComplexNumber second)
    {
        ComplexNumber newNumber = new ComplexNumber(
            first.RealPart * second.RealPart - first.ImaginaryPart * second.ImaginaryPart,
            first.RealPart * second.ImaginaryPart + first.ImaginaryPart * second.RealPart);
        return newNumber;
    }

    public static ComplexNumber operator /(ComplexNumber first, ComplexNumber second)
    {
        if (second.RealPart == 0 && second.ImaginaryPart == 0)
        {
            throw new DivideByZeroException("Can't devide by zero.");
        }

        double denominator = second.RealPart * second.RealPart + second.ImaginaryPart * second.ImaginaryPart;
        ComplexNumber newNumber = new ComplexNumber(
            (first.RealPart * second.RealPart + first.ImaginaryPart * second.ImaginaryPart) / denominator,
            (first.ImaginaryPart * second.RealPart - first.RealPart * second.ImaginaryPart) / denominator);
        return newNumber;
    }

    public static bool operator ==(ComplexNumber first, ComplexNumber second)
    {
        if (first.Equals(second))
        {
            return true;
        }
        return false;
    }

    public static bool operator !=(ComplexNumber first, ComplexNumber second)
    {
        return !(first == second);
    }

    public override int GetHashCode()
    {
        int hashCode = this.RealPart.GetHashCode() ^ this.ImaginaryPart.GetHashCode();
        return hashCode;
    }

    public override bool Equals(object other)
    {
        if (other is ComplexNumber)
        {
            ComplexNumber otherNumber = other as ComplexNumber;
            if (this.RealPart == otherNumber.RealPart && this.ImaginaryPart == otherNumber.ImaginaryPart)
            {
                return true;
            }
        }
        return false;
    }

    public override string ToString()
    {
        String number = "";
        if (this.RealPart == 0 && this.ImaginaryPart == 0)
        {
            number = "0";
        }
        if (this.RealPart != 0)
        {
            number += this.RealPart;
        }
        if (this.ImaginaryPart < 0)
        {
            number += this.imaginaryPart+"i";
        }
        if (this.ImaginaryPart > 0)
        {
            number += "+" + this.ImaginaryPart + "i";
        }
        return number;
    }

    public static implicit operator ComplexNumber(double number)
    {
        ComplexNumber newNumber = new ComplexNumber(number, 0);
        return newNumber;
    }

    public static explicit operator double(ComplexNumber number)
    {
        if (number.ImaginaryPart != 0)
        {
            return double.NaN;
        }
        return number.RealPart;
    }

    public double this[int index]
    {
        get
        {
            if (index == 0)
            {
                return this.RealPart;
            }
            if (index == 1)
            {
                return this.ImaginaryPart;
            }
            throw new ArgumentOutOfRangeException("Index could be onli 0 or 1.");
        }
        set
        {
            if (index == 0)
            {
                this.RealPart = value;
            }
            if (index == 1)
            {
                this.ImaginaryPart = value;
            }
            throw new ArgumentOutOfRangeException("Index could be onli 0 or 1.");
        }
    }

}
